/**
 * @author Ahammer
 * @date   2009 11
 * @update 
 */

/*
 * This file is part of Iqm.
 * Copyright (c) 2010-2011 Helmut Ahammer
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package op;

import java.awt.RenderingHints;
import java.awt.image.DataBuffer;
import java.awt.image.renderable.ParameterBlock;
import javax.media.jai.JAI;
import javax.media.jai.ParameterBlockJAI;
import javax.media.jai.PlanarImage;
import javax.media.jai.RenderedOp;
import javax.media.jai.operator.DFTDescriptor;
import javax.media.jai.operator.IDFTDescriptor;


/**
 * This is the main image processing class
 * There exist two approaches:
 * A user defined JAI operator is just called 
 * or:
 * The actual processing is implemented in this class 
 */
public class IqmDFTOperator{ 


  public IqmDFTOperator() {
	  //WARNING: Don't declare fields here
	  //Fields declared here aren't thread safe!   
  }
  /**
   * 
   * @param ParametrBlockJAI pb
   */
  public Object run(ParameterBlockJAI pbJAI){
	  Object ob = null;
	  //ob = JAI.create("IqmCalcImage".toLowerCase(), pb, null);  
	  
	  PlanarImage pi    = (PlanarImage) pbJAI.getSource(0);
	  int scale 	    = pbJAI.getIntParameter(0);
	  int resultOptions = pbJAI.getIntParameter(1);
	  
	  //RenderingHints rh = new RenderingHints(JAI.KEY_BORDER_EXTENDER, BorderExtender.createInstance(BorderExtender.BORDER_COPY));	
	  RenderingHints rh = null;	
	  ParameterBlock pb = new ParameterBlock();
	  pb.addSource(pi);	
	  
	  if (scale == 0){ //none
		  pb.add(DFTDescriptor.SCALING_NONE);	
	  }
	  if (scale == 1){ //unitary
		  pb.add(DFTDescriptor.SCALING_UNITARY);	
	  }
	  if (scale == 2){ //dimensions
		  pb.add(DFTDescriptor.SCALING_DIMENSIONS);	
	  }
	  pb.add(DFTDescriptor.REAL_TO_COMPLEX);
	  ob = JAI.create("DFT", pb, rh);

	  //PlanarImage mag  = null;
	  //PlanarImage phase = null;
	  //--------------------------------------------------------------------
	  if (resultOptions == 0){ //Power
	      pb.removeSources();
	      pb.removeParameters();
		  pb.addSource(ob);
		  ob = JAI.create("MagnitudeSquared", pb); 
	  }
	  if (resultOptions == 1){ //Magnitude
		  pb.removeSources();
		  pb.removeParameters();
		  pb.addSource(ob);
		  ob = JAI.create("Magnitude", pb); 
	  }

	  if (resultOptions == 2){ //Phase
	      pb.removeSources();
	      pb.removeParameters();
		  pb.addSource(ob);
		  ob = JAI.create("Phase", pb);  
	  }
	  if (resultOptions == 3){ //Real
	      //pi = JAI.create("bandselect", pi, new int[] {0});  //zu hell in der Darstellung!!!		  
		  double[][] matrix = null;
		  System.out.println("Number of Bands: " + ((PlanarImage) ob).getNumBands());
	      if (((PlanarImage) ob).getNumBands() == 2 ){
	    	  matrix = new double[][]{ { 1.0d, 0.0d, 0.0d} };  
		      ob = JAI.create( "bandcombine", new ParameterBlock().addSource(ob).add(matrix), null);	
	      }
	      if (((PlanarImage) ob).getNumBands() == 6 ){ //RGB
	    	  matrix = new double[][]{ { 1.0d, 0.0d, 0.0d, 0.0d, 0.0d, 0.0d, 0.0d} }; 
		      PlanarImage pi1 = JAI.create( "bandcombine", new ParameterBlock().addSource(ob).add(matrix), null);	
	    	  matrix = new double[][]{ { 0.0d, 0.0d, 1.0d, 0.0d, 0.0d, 0.0d, 0.0d} }; 
		      PlanarImage pi2 = JAI.create( "bandcombine", new ParameterBlock().addSource(ob).add(matrix), null);	
	    	  matrix = new double[][]{ { 0.0d, 0.0d, 0.0d, 0.0d, 1.0d, 0.0d, 0.0d} }; 
		      PlanarImage pi3 = JAI.create( "bandcombine", new ParameterBlock().addSource(ob).add(matrix), null);	
			  pb.removeSources();
			  pb.removeParameters();
		      pb.setSource(pi1, 0);
		      pb.setSource(pi2, 1);
		      pb.setSource(pi3, 2);			
			  ob = JAI.create("bandmerge", pb, null);			      
	      }
	       
	  }
	  if (resultOptions == 4){ //Imaginary part
	      //pi = JAI.create("bandselect", pi, new int[] {0});  //zu hell in der Darstellung!!!
		  double[][] matrix = null;
	      if (((PlanarImage) ob).getNumBands() == 2 ){ //Grey
	    	  matrix = new double[][]{ { 0.0d, 1.0d, 0.0d} }; 
		      ob = JAI.create( "bandcombine", new ParameterBlock().addSource(ob).add(matrix), null);	
	      }
	      if (((PlanarImage) ob).getNumBands() == 6 ){ //RGB
	    	  matrix = new double[][]{ { 0.0d, 1.0d, 0.0d, 0.0d, 0.0d, 0.0d, 0.0d} }; 
		      PlanarImage pi1 = JAI.create( "bandcombine", new ParameterBlock().addSource(ob).add(matrix), null);	
	    	  matrix = new double[][]{ { 0.0d, 0.0d, 0.0d, 1.0d, 0.0d, 0.0d, 0.0d} }; 
		      PlanarImage pi2 = JAI.create( "bandcombine", new ParameterBlock().addSource(ob).add(matrix), null);	
	    	  matrix = new double[][]{ { 0.0d, 0.0d, 0.0d, 0.0d, 0.0d, 1.0d, 0.0d} }; 
		      PlanarImage pi3 = JAI.create( "bandcombine", new ParameterBlock().addSource(ob).add(matrix), null);	
			  pb.removeSources();
			  pb.removeParameters();
		      pb.setSource(pi1, 0);
		      pb.setSource(pi2, 1);
		      pb.setSource(pi3, 2);			
			  ob = JAI.create("bandmerge", pb, null);			      
	      }
	  }
	  
	  //Periodic shift: corners are shifted to the center of the image---------- 
	  pb.removeSources();
	  pb.removeParameters();
	  pb.addSource(ob);
	  //pb.add(shiftX); //default: Width/2
	  //pb.add(shiftY);	//default: Height/2
	  ob = JAI.create("PeriodicShift", pb);
	  
	  
	  
//	  //Normalization of result
//	  //double min = 0d;
//	  double max = 0d;
//	  pb.removeSources();
//	  pb.removeParameters();
//	  pb.addSource(ob);
//	  RenderedOp extrema = JAI.create("extrema", pb);
//	  //double[] allMins = (double[])extrema.getProperty("minimum");
//	  double[] allMaxs = (double[])extrema.getProperty("maximum");
//	  for (int i = 0; i < allMaxs.length; i++){
//		  max = Math.max(allMaxs[i], max);
//	  }  
//	  pb.removeSources();
//	  pb.removeParameters();
//	  pb.addSource(ob);
//	  pb.add(new double[]{255d/max});
//	  ob = JAI.create("rescale", pb);
	  
//	  //Change float to byte----------------------------------------------------
//	  pb.removeSources();
//	  pb.removeParameters();
//	  pb.addSource(ob);
//	  pb.add(DataBuffer.TYPE_BYTE);
//	  ob = JAI.create("format", pb);
	  

	  
//	  //Reconstruct--------------------------------------------------------------
//	  pb.removeSources();
//	  pb.removeParameters();
//	  pb.addSource(mag);
//	  pb.addSource(phase);  
//	  pb.addSource(IDFTDescriptor.SCALING_DIMENSIONS);
//	  pb.addSource(IDFTDescriptor.COMPLEX_TO_REAL);
//	  PlanarImage ptc = JAI.create("PolarToComplex", pb);	  
//	  pb.removeSources();
//	  pb.removeParameters();
//	  pb.addSource(ptc);	
//	  ob = JAI.create("IDFT", pb);
//	  
//	  //Change float to byte
//	  pb.removeSources();
//	  pb.removeParameters();
//	  pb.addSource(ob);
//	  pb.add(DataBuffer.TYPE_BYTE);
//	  ob = JAI.create("format", pb);
//	  
//	  //Crop to original size
//	  pb.removeSources();
//	  pb.removeParameters();
//	  pb.addSource(ob);
//	  pb.add(0f);
//	  pb.add(0f);
//	  pb.add((float)pi.getWidth());
//	  pb.add((float)pi.getHeight());
//	  ob = JAI.create("Crop", pb);
//    //--------------------------------------------------------------------------
	
//	  LookJDFTFrame f = new LookJDFTFrame();
//	  f.createAndShowGUI();
//	  f.setVisible(true);
//	  f.setImage((PlanarImage)ob);
	  
	  return ob;
  }
}
